#include "stdafx.h"

#include "Business/ArbitrageLegs.h"
#include "Service/MarketStorage.h"
#include "Business/BollingerCalculator.h"
#include "Utils/Logger.h"

ArbitrageLegs::ArbitrageLegs(MarketStorage const& marketStorage, ArbitrageContracts const& contracts,Direction::TYPE fartherDirection,Band const& band) 
:m_fartherOpenLeg(marketStorage.GetMarket(contracts.GetFarther()),fartherDirection,Operation::OPEN),
m_nearbyOpenLeg(marketStorage.GetMarket(contracts.GetNearby()),m_fartherOpenLeg.NegateDirection(),Operation::OPEN),
m_fartherOffsetLeg(marketStorage.GetMarket(contracts.GetFarther()),m_fartherOpenLeg.NegateDirection(),Operation::OFFSET_TODAY),
m_nearbyOffsetLeg(marketStorage.GetMarket(contracts.GetNearby()),m_fartherOpenLeg.GetDirection(),Operation::OFFSET_TODAY),
m_band(band),
m_minorOpenLeg(contracts.IsMajorEqualFarther() ? m_nearbyOpenLeg : m_fartherOpenLeg),
m_majorOpenLeg(contracts.IsMajorEqualFarther() ? m_fartherOpenLeg : m_nearbyOpenLeg),
m_minorOffsetLeg(contracts.IsMajorEqualFarther() ? m_nearbyOffsetLeg : m_fartherOffsetLeg),
m_majorOffsetLeg(contracts.IsMajorEqualFarther() ? m_fartherOffsetLeg : m_nearbyOffsetLeg)
{
}

ArbitrageLegs::ArbitrageLegs(ArbitrageLegs const& other) :m_fartherOpenLeg(other.GetFartherOpenLeg()),
m_nearbyOpenLeg(other.GetNearbyOpenLeg()),
m_fartherOffsetLeg(other.GetFartherOffsetLeg()),
m_nearbyOffsetLeg(other.GetNearbyOffsetLeg()),
m_band(other.GetBand()),
m_minorOpenLeg(other.IsMajorEqualFarther() ? m_nearbyOpenLeg : m_fartherOpenLeg),
m_majorOpenLeg(other.IsMajorEqualFarther() ? m_fartherOpenLeg : m_nearbyOpenLeg),
m_minorOffsetLeg(other.IsMajorEqualFarther() ? m_nearbyOffsetLeg : m_fartherOffsetLeg),
m_majorOffsetLeg(other.IsMajorEqualFarther() ? m_fartherOffsetLeg : m_nearbyOffsetLeg)
{
}

ArbitrageLegs ArbitrageLegs::CreateBearish(MarketStorage const& marketStorage,ArbitrageContracts const& contracts)
{
	return ArbitrageLegs(marketStorage,contracts, Direction::BUY,Band::CreateBearish());
}

ArbitrageLegs ArbitrageLegs::CreateBullish(MarketStorage const& marketStorage,ArbitrageContracts const& contracts)
{
	return ArbitrageLegs(marketStorage,contracts, Direction::SELL,Band::CreateBullish());
}

ArbitrageLegs ArbitrageLegs::Create(MarketStorage const& marketStorage,Band const& band,ArbitrageContracts const& contracts)
{
	return band.IsSameType(Band::CreateBearish()) ? 
		CreateBearish(marketStorage,contracts) : CreateBullish(marketStorage,contracts);
}

bool ArbitrageLegs::UpdateBand(Band const& band)
{
	if (band.IsSameType(m_band))
	{
		m_band = band;
		return true;
	}
	return false;
}

double ArbitrageLegs::GetProfit(double balance, int quantity) const
{
	int sign = m_band.IsSameType(Band::CreateBearish()) ? 1 : -1;
	double basicProfit = GetOffsetBalance() - balance;
	if (DoubleEqual(0.00,basicProfit))
	{
		return 0.00;
	}
	return basicProfit * quantity * sign * m_majorOpenLeg.GetMarket().GetMultiple();
}

double ArbitrageLegs::GetOpenBalance(Dealing const& openedDealing) const
{
	if (GetFartherOpenLeg().Match(openedDealing.GetContract(),openedDealing.GetDirection(), openedDealing.GetOperation()))
	{
		return openedDealing.GetOrderPrice() - GetNearbyOpenLeg().GetPrice();
	}
	else if (GetNearbyOpenLeg().Match(openedDealing.GetContract(),openedDealing.GetDirection(), openedDealing.GetOperation()))
	{
		return GetFartherOpenLeg().GetPrice() - openedDealing.GetOrderPrice();
	}
#ifndef LOG4CPLUS_DISABLE_ERROR
	LightLogger::Error("get dealing open balance throw 1");
#endif
	throw 1;
}

double ArbitrageLegs::GetOffsetBalance(Dealing const& openedDealing) const
{
	if (GetFartherOpenLeg().Match(openedDealing.GetContract(),openedDealing.GetDirection(), openedDealing.GetOperation()))
	{
		return openedDealing.GetOrderPrice() - GetNearbyOffsetLeg().GetPrice();
	}
	else if (GetNearbyOpenLeg().Match(openedDealing.GetContract(),openedDealing.GetDirection(), openedDealing.GetOperation()))
	{
		return GetFartherOffsetLeg().GetPrice() - openedDealing.GetOrderPrice();
	}
#ifndef LOG4CPLUS_DISABLE_ERROR
	LightLogger::Error("get dealing offset balance throw 1");
#endif
	throw 1;
}

